/** ****************************************************************************
 * CopyRight (C) 2012 Sharadendu Sinha.
 * Licensing : FreeBSD 
 *
 * @(#) $Id$
 */
package com.sps.signalling;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

import com.sps.signalling.exceptions.SignallingException;

/**
 * This class provides implementation of a Slot.
 * 
 * @version 1.1
 * @author sharadendu
 */
public class Slot
	extends AbstractInvokable
{
	/**
	 * Every slot is associated with {@link SlotHandler} which eventually
	 * gets invoked by the {@link Executor} provided by the {@link SlotProvider}
	 * 
	 * @version 1.1
	 * @author sharadendu
	 */
	public static interface SlotHandler
	{
		void handleSlotInvcocation(Slot slot, Object... objects);
	}

	/** The {@link SlotHandler} for this slot */
	private final SlotHandler	slotHandler;

	/**
	 * Constructor for Slot. To be used if reflection is not desired.
	 * 
	 * @param name The name of this slot
	 * @param invokableProvider The {@link InvokableProvider} for this slot.
	 *            This usually is a {@link SignallingEntity}; unless you
	 *            implement the {@link SlotProvider} interface
	 * @param slotHandler The {@link SlotHandler} for this slot
	 */
	public Slot(String name, InvokableProvider invokableProvider,
		SlotHandler slotHandler)
	{
		super(name, invokableProvider);
		if(slotHandler == null)
		{
			throw new SignallingException(SignallingException.SLOT_HANDLER_NULL);
		}
		this.slotHandler = slotHandler;
	}

	/**
	 * Constructor for Slot. To be used if reflection is desired. Here
	 * invokableProvider will be treated as the instance object for {@link Slot}
	 * method
	 * 
	 * @param name name The name of this slot
	 * @param invokableProvider invokableProvider The {@link InvokableProvider}
	 *            for this slot. This usually is a {@link SignallingEntity};
	 *            unless you implement the {@link SlotProvider} interface
	 * @param slotMethodName This is the method name of the {@link Method} that
	 *            will be invoked when a Slot is invoked
	 * @param parameterTypes This is the parameter types of the {@link Method}
	 *            that will be invoked when a Slot is invoked
	 * @throws SignallingException if {@link Method} is not found in
	 *             invokableProvider
	 */
	public Slot(String name, InvokableProvider invokableProvider,
		String slotMethodName,
		@SuppressWarnings("rawtypes") Class[] parameterTypes)
		throws SignallingException
	{
		this(name, invokableProvider, slotMethodName, parameterTypes,
			invokableProvider);
	}

	/**
	 * Constructor for Slot. To be used if reflection is desired.
	 * 
	 * @param name name The name of this slot
	 * @param invokableProvider invokableProvider The {@link InvokableProvider}
	 *            for this slot. This usually is a {@link SignallingEntity};
	 *            unless you implement the {@link SlotProvider} interface
	 * @param slotMethodName This is the method name of the {@link Method} that
	 *            will be invoked when a Slot is invoked
	 * @param parameterTypes This is the parameter types of the {@link Method}
	 *            that will be invoked when a Slot is invoked
	 * @param instance This is the instance of the Object that contains the
	 *            methods to be invoked during Slot invocation
	 * @throws SignallingException if {@link Method} is not found in instance
	 */
	public Slot(String name, InvokableProvider invokableProvider,
		String slotMethodName,
		@SuppressWarnings("rawtypes") Class[] parameterTypes, Object instance)
		throws SignallingException
	{
		super(name, invokableProvider);
		this.slotHandler = new ReflectiveSlotHandler(slotMethodName,
			parameterTypes, instance);
	}

	/**
	 * @see com.sps.signalling.Invokable#getType()
	 */
	@Override
	public Type getType()
	{
		return Type.SLOT;
	}

	/**
	 * @see com.sps.signalling.Invokable#invoke(com.sps.signalling.InvokableConnection.Type,
	 *      java.lang.Object[])
	 */
	@Override
	public void invoke(final InvokableConnection.Type invocationType,
		final Object... paramObjects)
	{
		final SlotProvider slotProvider = (SlotProvider)getProvider();
		slotProvider.getExecutor(invocationType).execute(new Runnable()
		{
			@Override
			public void run()
			{
				slotHandler.handleSlotInvcocation(Slot.this, paramObjects);
			}
		});
	}
}
